#include <pthread.h>
#include <unistd.h>

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct _item {
      int v;
      int i;
      int j; 
} ITEM; 

int m, k, **a, *pi, substitui_maior, substitui_menor, substitui_maior_pi, substitui_menor_pi;
 
ITEM maior, menor, maior_pi, menor_pi, *maior_por_linha, *menor_por_linha;

void libera_matriz (int m, int n, int **v){
    int i;
    for (i=0; i<m; i++) free (v[i]);
    free (v);
}

int **aloca_matriz(int m, int n) {
	int **v; 
	int i;    
	if (m < 1 || n < 1) { 
		printf("Erro: Parametro invalido");
		return NULL;
	}

	v = (int **) malloc (m * sizeof(int *));
	if (v == NULL) {
		printf("Erro: Memoria Insuficiente");
		return NULL;
	}

	for (i = 0; i < m; i++) {
		v[i] = (int*) malloc (n * sizeof(int));
		if (v[i] == NULL) {
			printf("Erro: Memoria Insuficiente");
			return NULL;
		}
	}
	return v; 
}

int *aloca_vetor(int m) {
	int *v; 

	if (m < 1) { 
		printf("Erro: Parametro invalido");
		return NULL;
	}

	v = (int*) malloc (m * sizeof(int));
	if (v == NULL) {
		printf("Erro: Memoria Insuficiente");
		return NULL;
	}

	return v;
}

void *run(void *num) {

	long long int i = (long long int) num;
	int j;

	for(j = 0; j < k; j++) {
		pi[i] += a[i][j] * a[i][j];

		substitui_maior = 0;
		substitui_menor = 0;

		if (j == 0) {
			substitui_maior = 1;
			substitui_menor = 1;
		} else {
			if (a[i][j] > maior_por_linha[i].v) 
				substitui_maior = 1;

			if (a[i][j] < menor_por_linha[i].v) 
				substitui_menor = 1;
			
		}
		if (substitui_maior == 1) {
			maior_por_linha[i].v = a[i][j];
			maior_por_linha[i].j = j;
			maior_por_linha[i].i = i;
		}
		if (substitui_menor == 1) {
			menor_por_linha[i].v = a[i][j];
			menor_por_linha[i].j = j;
			menor_por_linha[i].i = i;
		}
	}			

	pthread_exit(NULL);
}

int main(void) {
	while(1) {
		int i, j;

		pthread_t *threads;
		srand(time(NULL));

		printf("\nEntre com as dimensões da matriz: ");
		scanf ("%d %d", &m, &k);
	
		if ((m == 0 && k == 0) || (m != k)) break;

		double ini = time(0); // tempo de inicio
		
		a = aloca_matriz(m, k);
		pi = aloca_vetor(m);

		maior_por_linha = (ITEM *) malloc (m * sizeof(ITEM));
		menor_por_linha = (ITEM *) malloc (m * sizeof(ITEM));

		// inicializa matriz com valores aleatorios (a) e o vetor produto interno (pi) com zero.
		for(i = 0; i < m; i++) {
			for(j = 0; j < k; j++) {
				a[i][j] = rand() % 5; 
			}
			pi[i] = 0;
		}

		threads = (pthread_t*) malloc (m * sizeof(pthread_t));
	
		// cria as threads
		for (i = 0; i < m; i++) {
			pthread_create(&threads[i], NULL, run, (void *) i);
		}

		for(i = 0;i < m; i++)
			pthread_join(threads[i], NULL);		


		//calcula maiores
		for (i = 0; i < m; i++) {
			substitui_maior = 0;
			substitui_menor = 0;
			substitui_maior_pi = 0;
			substitui_menor_pi = 0;

			if (i == 0) {
				substitui_maior = 1;
				substitui_menor = 1;
				substitui_maior_pi = 1;
				substitui_menor_pi = 1;
			} else {
				if (maior_por_linha[i].v > maior.v) 
					substitui_maior = 1;

				if (menor_por_linha[i].v < menor.v) 
					substitui_menor = 1;

				if (pi[i] > maior_pi.v) 
					substitui_maior_pi = 1;
				
				if (pi[i] < menor_pi.v) 
					substitui_menor_pi = 1;
			}
			if (substitui_maior == 1) {
				maior.v = maior_por_linha[i].v;
				maior.j = maior_por_linha[i].j;
				maior.i = maior_por_linha[i].i;
			}
			if (substitui_menor == 1) {
				menor.v = menor_por_linha[i].v;
				menor.j = menor_por_linha[i].j;
				menor.i = menor_por_linha[i].i;
			}
			if (substitui_maior_pi == 1) {
				maior_pi.v = pi[i];
				maior_pi.i = i;
			}
			if (substitui_menor_pi == 1) {
				menor_pi.v = pi[i];
				menor_pi.i = i;
			}
		}

		printf("\n--------------------\n");
		
		printf("matriz\n");
		/*	
		for(i = 0; i < m; i++) {
			for(j = 0; j < k; j++) {
				printf("%d ", a[i][j]); 
			}
			printf("\n");
		} 
		printf("\nMaior: %d em (%d, %d)", maior.v, maior.i, maior.j); 
		printf("\nMenor: %d em (%d, %d)", menor.v, menor.i, menor.j); 

		printf("\n--------------------\n");
		printf("vetor produto interno\n");

		for(i = 0; i < m; i++) {
			printf("%d ", pi[i]); 
		}
		*/
		printf("\n\nMaior PI: %d em (%d)", maior_pi.v, maior_pi.i); 
		printf("\nMenor PI: %d em (%d)", menor_pi.v, menor_pi.i); 

		printf("\n--------------------\n");

		libera_matriz(m, k, a);
		free(pi);

		printf("Tempo de Execucao: %f segundos\n", time(0) - ini);


 	}
	return 0;
}

